//! @file   lc_normal_iterator.h
//! @brief  
//! @author Sayan Chaliha
//! @date   September, 2011
//!
//! 
#ifndef _LC_NORMAL_ITERATOR_H
#define _LC_NORMAL_ITERATOR_H

#include "libcyan_internal.h"
#include "lc_iterator.h"
#include "lc_object.h"

namespace cyan {
  template <typename I, typename C>
  class CYAN_API NormalIterator : public Object {
  public:
    typedef typename IteratorTraits<I>::IteratorCategory  IteratorCategory;
    typedef typename IteratorTraits<I>::ValueType         ValueType;
    typedef typename IteratorTraits<I>::DifferenceType    DifferenceType;
    typedef typename IteratorTraits<I>::Pointer           Pointer;
    typedef typename IteratorTraits<I>::Reference         Reference;

    NormalIterator() : current_(I()) {
    }

    explicit NormalIterator(const I& i) : current_(i) {
    }

    template <typename J>
    NormalIterator(const NormalIterator<J, C>& i) : current_(i.base()) {
    }

    const I& base() const {
      return this->current_;
    }

    Reference operator *() const {
      return *this->current_;
    }

    Reference operator [](const DifferenceType& n) const {
      return *(this->current_[n]);
    }

    Pointer operator ->() const {
      return this->current_;
    }

    NormalIterator& operator ++() {
      this->current_++;
      return *this;
    }

    NormalIterator& operator ++(Int) {
      NormalIterator returnValue = *this;
      this->current_++;
      return returnValue;
    }

    NormalIterator& operator --() {
      this->current_--;
      return *this;
    }

    NormalIterator& operator --(Int) {
      NormalIterator returnValue = *this;
      this->current_--;
      return returnValue;
    }

    NormalIterator& operator +=(const DifferenceType& value) {
      this->current_ += value;
      return *this;
    }

    NormalIterator operator +(const DifferenceType& value) const {
      return NormalIterator(this->current_ + value);
    }

    NormalIterator& operator -=(const DifferenceType& value) {
      this->current_ -= value;
      return *this;
    }

    NormalIterator operator -(const DifferenceType& value) const {
      return NormalIterator(this->current_ - value);
    }

  protected:
    I current_;
  };

  template <typename L, typename R, typename T>
  Bool CYAN_API operator ==(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() == rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator ==(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() == rhs.base();
  }

  template <typename L, typename R, typename T>
  Bool CYAN_API operator !=(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() != rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator !=(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() != rhs.base();
  }

  template <typename L, typename R, typename T>
  Bool CYAN_API operator <(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() < rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator <(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() < rhs.base();
  }

  template <typename L, typename R, typename T>
  Bool CYAN_API operator >(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() > rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator >(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() > rhs.base();
  }

  template <typename L, typename R, typename T>
  Bool CYAN_API operator <=(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() <= rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator <=(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() <= rhs.base();
  }

  template <typename L, typename R, typename T>
  Bool CYAN_API operator >=(const NormalIterator<L, T>& lhs,
      const NormalIterator<R, T>& rhs) {
    return lhs.base() >= rhs.base();
  }

  template <typename J, typename T>
  Bool CYAN_API operator >=(const NormalIterator<J, T>& lhs,
      const NormalIterator<J, T>& rhs) {
    return lhs.base() >= rhs.base();
  }

  template <typename I, typename J, typename C>
  typename NormalIterator<I, C>::DifferenceType  CYAN_API
  operator -(const NormalIterator<I, C>& lhs,
      const NormalIterator<J, C>& rhs) {
    return lhs.base() - rhs.base();
  }
}

#endif /* _LC_NORMAL_ITERATOR_H */
